﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Core.DatabaseHelpers;
using Core.Interfaces;
using Core.Interfaces.IDAO;
using Core.Unity;
using Microsoft.Practices.Unity;

namespace Core.DAO
{
    public abstract class AbstractDAO<T> :IDAO<T> where T : IDomainObject
    {
        protected readonly IConnection Connection;
        protected readonly string TableName;
        protected readonly int ColumnCount;

        protected AbstractDAO(IConnection connection)
        {
            Connection = connection;
            var attribute =
                (TableAttribute) Attribute.GetCustomAttribute(typeof (T), typeof (TableAttribute));
            TableName = attribute.Name;
            var listOfAtr = typeof (T).GetProperties().Select(c => c.GetCustomAttributes(typeof (ColumnAttribute),false)).ToList();
            ColumnCount = listOfAtr.Count();
        }

        protected abstract void GetDependendModels(object domainobject, object[] row); 

        public virtual  List<T> GetAll(bool is_lasy = false) 
        {
            var result = new List<T>();
            var query = Connection.ExecuteSelectQuery<T>(Connection.SelectQuery<T>(TableName, "",is_lasy),is_lasy);
            foreach (object[] objectse in query)
            {
                var district = ResolverContainer.Resolver.Resolve<T>();
                district.ConstructIt(objectse);
                if (is_lasy)
                {
                    GetDependendModels(district, objectse);
                }
                result.Add(district);
            }
            return result;

        }

        public virtual List<T> GetBySelect( string where ,bool is_lasy= false)
        {
            var result = new List<T>();
            var query = Connection.ExecuteSelectQuery<T>(Connection.SelectQuery<T>(TableName, where, is_lasy), is_lasy);
            foreach (object[] objectse in query)
            {
                var district = ResolverContainer.Resolver.Resolve<T>();
                district.ConstructIt(objectse);
                if (is_lasy)
                {
                    GetDependendModels(district, objectse);
                }
                result.Add(district);
            }
            return result;
        }
    
        public  List<T> GetAllByField(string fielsName, object value)
        {
            var result = new List<T>();
            var s = value.ToString();
            if (value.GetType().Name =="String")
            {
                s = string.Format("'{0}'", value);
            }
            var query = Connection.ExecuteSelectQuery<T>(Connection.SelectQuery<T>(TableName, fielsName + "=" + s),false);
            foreach (object[] objectse in query)
            {
                var district = ResolverContainer.Resolver.Resolve<T>();
                district.ConstructIt(objectse);
                result.Add(district);
            }
            return result;
        }


        public virtual bool SaveOrUpdateAndCommit(IDomainObject domainObject)
        {
            bool result = false;
            var v = ColumnHelper.GetColumValue<T>(domainObject);
            
            var s = "";

            s = !domainObject.FromDatabase() ? Connection.InsertQuery(TableName, v) :
                Connection.UpdateQuery(TableName, v, ColumnHelper.GetPkNameAndValue(domainObject).Key + "=" + ColumnHelper.GetPkNameAndValue(domainObject).Value);
            s += ";";
            if (ColumnHelper.HasManyToMany<T>())
            {
                try
                {
                    Connection.ExecuteQuery(s);
                    result = true;
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error,
                                    MessageBoxDefaultButton.Button1);
                    Connection.CloseConnection();

                }
                var pp = ColumnHelper.GetHasManyField<T>();
                var b = (IEnumerable)pp.GetValue(domainObject,null);
                s = "";
                var o = GetAll(false).Last();
                var opk = ColumnHelper.GetPkNameAndValue(o);
                foreach (object dependent in b)
                {
                    var ss = ColumnHelper.GetPkNameAndValue(dependent);
                    var througt = (ColumnAttribute) pp.GetCustomAttributes(typeof (ColumnAttribute), false).First();
                    var values = new Dictionary<string, string>();
                    values.Add(ss.Key,ss.Value);
                    values.Add(opk.Key,opk.Value);
                    s += Connection.InsertQuery(througt.Through,values)+';';
                }
                try
                {
                    Connection.ExecuteQuery(s);
                    result = true;
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error,
                                    MessageBoxDefaultButton.Button1);
                    Connection.CloseConnection();

                }
            }
            else
            {
                try
                {
                    Connection.ExecuteQuery(s);
                    result = true;
                }
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error,
                                    MessageBoxDefaultButton.Button1);
                    Connection.CloseConnection();

                }
            }
    
            
            return result;
        }


        public virtual bool Delete(IDomainObject domainObject)
        {
             bool result = false;
            var v = ColumnHelper.GetPrimaryKeys<T>(domainObject);

            var s = Connection.DeleteQuery(TableName, v);
            try
            {
                Connection.ExecuteQuery(s);
                result = true;
            }
            catch (Exception exception)
            {
                System.Data.SqlClient.SqlException e =  (SqlException) exception;
                
                MessageBox.Show(domainObject.GetErrorByCode(e.Number), "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error,
                                MessageBoxDefaultButton.Button1);
                Connection.CloseConnection();
                
            }
            
            
            return result;
        }
    }
}
